package cn.weakup.designpattern.c_structural.proxy.usepattern;

import cn.weakup.designpattern.c_structural.proxy.Select;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.FactoryBean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author lixj
 * @version 1.0.0
 * @date 2022/6/5
 * @desc 代理类定义
 *
 * 如果阅读过mybatis源码，是可以看到这样的⼀个类； MapperFactoryBean ，这⾥我们也模
 * 拟⼀个这样的类，在⾥⾯实现我们对代理类的定义。
 *
 * 通过继承 FactoryBean ，提供bean对象，也就是⽅法； T getObject() 。
 *
 * 在⽅法 getObject() 中提供类的代理以及模拟对sql语句的处理，这⾥包含了⽤户调⽤dao层⽅法
 * 时候的处理逻辑。
 *
 * 还有最上⾯我们提供构造函数来透传需要被代理类， Class<T> mapperInterface ，在mybatis
 * 中也是使⽤这样的⽅式进⾏透传。
 *
 * 另外 getObjectType() 提供对象类型反馈，以及 isSingleton() 返回类是单例的
 */
public class MapperFactoryBean<T> implements FactoryBean<T> {
    private Class<T> mapperInterface;

    public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    @Override
    public T getObject() throws Exception {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Select select = method.getAnnotation(Select.class);
                System.out.println("SQL：" + select.value().replace("#{uId}", args[0].toString()));
                return args[0];
            }
        };
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]
                        {mapperInterface}, handler);
    }

    @Override
    public Class<?> getObjectType() {
        return mapperInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
